In general, a program is sequences of instructions executed by a processor to cause an electronic system to perform various functions. An electronic system may be, for example, a desktop, laptop or palmtop computer, or an electronic device such as a personal digital assistant (PDA), cellular phone or network access device. Typically, a programmer writes the program in a programming language, at which point the program is generally referred to as source code. The programmer runs a compiler to transform the source code into machine code, converting the program into a form that a processor can execute.
A compiler is a program that transforms source code into machine code. A front-end of the compiler receives the source code and generates an intermediate representation of the source code. The intermediate representation is also referred to herein as intermediate code. A back-end of the compiler uses the intermediate code to generate machine code.
A program may contain sections, commonly referred to as hotspots, that take more time to execute than other sections of the program, and thus negatively affect the program's performance. An example of a hotspot is a section of code at which a large number of incorrect branch predictions occur. A branch instruction is a point in a program at which a processor executes one set of instructions under one condition, and another set of instructions under another condition. Typically, the processor evaluates the branch before processing may continue, which thus slows processing. Some processors use a technique, commonly referred to as predictive branching, to predict, prior to the processor arriving at the branch instruction, which branch is the correct branch.
Instructions for a predicted branch are loaded in a pipeline prior to the processor arriving at the branch instruction. In general, a pipeline is used to load one instruction while a processor is executing another instruction. Without a pipeline, the processor retrieves, or fetches, an instruction from memory, executes the instruction, retrieves the next instruction, executes it, etc. Accordingly, the processor cannot execute an instruction until it is fetched. With a pipeline, instructions to be executed following an instruction currently being executed are fetched and held in a buffer while the processor is executing the current instruction. The buffer is typically closer to the processor than the memory in which the instructions are initially stored, which allows the processor to execute the program faster.
If instructions for a predicted branch are stored in a pipeline, but the predicted branch turns out to be the incorrect branch, the pipeline is flushed, i.e., instructions corresponding to the incorrect branch are cleared and replaced with instructions corresponding to the correct branch. Flushing a pipeline is expensive in terms of time, since the next and subsequent instructions must be loaded into the pipeline and proceed through the pipeline to be executed, before further progress in executing the program may be achieved. Consequently, flushing the pipeline causes a program to execute more slowly. Thus, a section of a program at which a large number of incorrect branch predictions and pipeline flushes occur typically cause a hotspot in the program.
A programmer can run a program and use a conventional tool commonly known as a profiler to analyze the program's performance and identify hotspots. In general, a profiler is a program that periodically collects and records samples of another program at user-defined time intervals while the program is running. The profiler records information regarding each section of the program sampled over a period of time, where such information includes, for example, the amount of time a section of the program takes to execute.
A programmer can use the information generated by the profiler to determine hotspots in a program. The programmer may choose to improve the program by manually inspecting and rewriting sections of the program that correspond to the hotspots. However, a profiler is unable to identify all of the hotspots in a single run of the program. Thus, if the programmer wants to further improve the code, the programmer runs the compiler to convert the revised source code into machine code, runs the revised program and uses the profiler to determine hotspots in the revised program. Accordingly, improvement in the program is limited to the hotspots identified each time the program is run. Improving the program using a conventional compiler and profiler therefore consumes a great deal of time and resources.